package gnss

import (
	"dgo/goutils/utils"
	"encoding/binary"
	"fmt"
	"time"
)

// 默认使用的全新的Buf
type Rtcm3RawBuf struct {
	Id            string
	buf           []byte
	size          uint16 // 数据长度
	rawlen        uint16 // rtcm数据体长度
	Tag           int
	ErrCode       int
	OutputWarning bool
	NewBufOnReset bool // Reset后,使用全新的Buf, 默认为true
	LogTypeStr    string
	decode_step   int
	OnErr         func(errcode int, err error) bool
	/**
	  包含头和CRC, rtcmBuf 默认是NewBuf, 由NewBufOnReset控制
	*/
	OnRtcmBuf func(rtcmBuf []byte)
}

const (
	RTCM_ERROR_DATA = -1
	RTCM_CRC_FAIL   = -2
	RTCM_BUG_DATA   = -3
	RTCM_NEED_MORE  = 0
	RTCM_OK         = 1
)

var MAX_RTCM3_MSG_SIZE uint16 = 1023
var MAX_RTCM3_RAW_SIZE uint16 = MAX_RTCM3_MSG_SIZE + 6 + 10 // RTCM32最大原始数据长度为:1029  , 10个为冗余字节

func NewRtcm32RawBuf(Id string) *Rtcm3RawBuf {
	return &Rtcm3RawBuf{
		Id:            Id,
		buf:           make([]byte, MAX_RTCM3_RAW_SIZE+1, MAX_RTCM3_RAW_SIZE+1),
		size:          0,
		rawlen:        0,
		decode_step:   -1,
		OutputWarning: true,
		NewBufOnReset: true,
	}
}

func (this *Rtcm3RawBuf) Reset() {
	if this.NewBufOnReset {
		this.buf = make([]byte, MAX_RTCM3_RAW_SIZE+1, MAX_RTCM3_RAW_SIZE+1)
	}
	this.size = 0
	this.rawlen = 0
}

func (this *Rtcm3RawBuf) GetRtcmMsgBuf() []byte {
	return this.buf[3 : this.rawlen+3]
}

/*
*

	获取整个RtcmBuf 包括 头和CRC
*/
func (this *Rtcm3RawBuf) GetRawBuf() []byte {
	return this.buf[0:this.size]
}

func (this *Rtcm3RawBuf) GetSize() uint16 {
	return this.size
}

func (this *Rtcm3RawBuf) GetMsgID() uint16 {
	msgid := GetBitU16(this.buf, 24, 12)
	return msgid
}

/*
*

	  Multiple Message Bit DF393

		1 indicates that more MSMs follow for given physical time and
		reference station ID
		0 indicates that it is the last MSM for given physical time and reference
		station ID
*/
func (this *Rtcm3RawBuf) GetMsmSyncFlag() byte {
	return GetBitU8(this.buf, 24+12+12+30, 1)
}

func (this *Rtcm3RawBuf) DecodeTime(t time.Time) (time.Time, bool) {
	msgid := int(this.GetMsgID())
	if RtcmIsObsMsm(int(this.GetMsgID())) {
		navisys := MsgID2NaviSys(msgid)
		return DecodeRtcmBufTime(this.buf, 24, navisys, t), true
	}
	return utils.ZeroTime, false
}

func (this *Rtcm3RawBuf) BufAsHexStr(spliter string) string {
	return utils.BufToHexStr(this.buf[:int(this.size)], 0, spliter)
}

func (this *Rtcm3RawBuf) InputBlockBuf(buf []byte) {
	for i := 0; i < len(buf); i++ {
		this.InputBuf(buf[i])
	}
}

/*
*

	-2:CRC错误
*/
func (this *Rtcm3RawBuf) InputBuf(b byte) int {
	if this.decode_step == -1 {
		this.decode_step = 0
		this.Reset()
	}
	if this.size == 0 { // 11010011
		this.buf[this.size] = b
		this.size++
		if b != 0xD3 {
			this.decode_step = -1
			return RTCM_ERROR_DATA
		}
		return RTCM_NEED_MORE
	} else if this.size == 1 {
		this.buf[this.size] = b
		this.size++
		if (b) > 3 { // 后两位是长度
			this.decode_step = -1
			return RTCM_ERROR_DATA
		}
		return RTCM_NEED_MORE
	} else if this.size == 3 {
		this.buf[this.size] = b
		this.size++

		len := binary.BigEndian.Uint16(this.buf[1:])
		this.rawlen = uint16(int(len) & 0x3FF) // 0x3FF 1111111111  1023
		return RTCM_NEED_MORE
	} else {
		this.buf[this.size] = b
		this.size++
		if this.size >= MAX_RTCM3_RAW_SIZE {
			if this.OnErr != nil {
				this.OnErr(RTCM_ERROR_DATA, fmt.Errorf("[%s]数据长度(%d)超长, 最大允许长度:%d, rtcmBuf:%s", this.Id, this.size, MAX_RTCM3_RAW_SIZE, this.BufAsHexStr("")))
			} else if this.OutputWarning {
				utils.Log.WarnTypef(this.LogTypeStr, "[%s]数据长度(%d)超长, 最大允许长度:%d, rtcmBuf:%s", this.Id, this.size, MAX_RTCM3_RAW_SIZE, this.BufAsHexStr(""))
			}
			this.decode_step = -1
			return RTCM_ERROR_DATA
		}

		if this.size == this.rawlen+6 { // 完整Buff
			crc1 := utils.CRC24QBuf(this.buf[0 : this.size-3])
			crc := GetBitU(this.buf[this.size-3:], 0, 24)
			if crc1 == crc {
				if this.OnRtcmBuf != nil {
					this.OnRtcmBuf(this.GetRawBuf())
				}
				this.decode_step = -1
				return RTCM_OK
			} else {
				if this.OnErr != nil {
					this.OnErr(RTCM_CRC_FAIL, fmt.Errorf("[%s]CRC校验失败,%.8X!=%.8X, rtcmBuf:%s", this.Id, crc1, crc, this.BufAsHexStr("")))
				} else if this.OutputWarning {
					utils.Log.WarnTypef(this.LogTypeStr, "[%s]CRC校验失败,%.8X!=%.8X, rtcmBuf:%s", this.Id, crc1, crc, this.BufAsHexStr(""))
				}
				this.decode_step = -1
				return RTCM_CRC_FAIL
			}
		}
		return RTCM_NEED_MORE
	}
}

/*
**

	返回值:
	   RTCM_ERROR_DATA, RTCM_CRC_FAIL, RTCM_OK
*/
func (this *Rtcm3RawBuf) InputRtcmBuf(buf []byte, start, l int) int {
	if buf[start] != 0xD3 {
		return RTCM_ERROR_DATA
	}
	i := start
	if l == 0 {
		l = len(buf[i:])
	}
	i += 1
	l1 := binary.BigEndian.Uint16(buf[i:])
	l1 = uint16(int(l1) & 0x3FF) // 0x3FF 1111111111  1023
	if (int(l1) + 6) != l {
		return RTCM_ERROR_DATA
	}

	crc1 := utils.CRC24QBuf(buf[start : l-3])
	crc := GetBitU(buf[start+l-3:], 0, 24)
	if crc1 == crc {
		copy(this.buf, buf[start:l])
		this.rawlen = l1
		this.size = uint16(l)
		return RTCM_OK
	} else {
		if this.OnErr != nil {
			this.OnErr(-1, fmt.Errorf("CRC校验失败,%d!=%d, rtcmBuf:%v", crc1, crc, buf[start:l]))
		} else if this.OutputWarning {
			utils.Log.Warnf("CRC校验失败,%d!=%d, rtcmBuf:%v", crc1, crc, buf[start:l])
		}
		return RTCM_CRC_FAIL
	}

}

/*
**

	outBuf, 包含RTCM消息体的数据流, start是数据包的开始位置，start + 3: rtcm消息体
	rtcmBufL: RTCM消息长度, 字节数
	返回: start + 3 + rtcml + 3
*/
func EncodeRtcm3HeadAndCrc(outBuf []byte, start int, rtcmBufL int) int {
	outBuf[start] = 0xD3

	startBitN := start * 8

	startBitN += 14

	// 长度
	SetBitU32(outBuf, startBitN, 10, uint32(rtcmBufL))
	startBitN += 10

	crcdatal := start + 3 + rtcmBufL // 3位 同步标记 + 保留位 + 长度（RTCM消息体）(10bit)
	crc1 := utils.CRC24QBuf(outBuf[start:crcdatal])

	startBitN += rtcmBufL * 8
	SetBitU32(outBuf, startBitN, 24, uint32(crc1))

	return start + 3 + rtcmBufL + 3

}

/*
**

	返回值:
	   RTCM_ERROR_DATA, RTCM_CRC_FAIL, RTCM_OK
*/
func CheckRtcm3Buf(buf []byte, start, l int) int {
	if buf[start] != 0xD3 {
		return RTCM_ERROR_DATA
	}
	i := start
	i += 1
	l1 := binary.BigEndian.Uint16(buf[i:])
	l1 = uint16(int(l1) & 0x3FF) // 0x3FF 1111111111  1023
	if (int(l1) + 6) != l {
		return RTCM_ERROR_DATA
	}

	crcdatal := l - 3
	crc1 := utils.CRC24QBuf(buf[start:crcdatal])
	crc := GetBitU(buf[start+l-3:], 0, 24)
	if crc1 == crc {
		return RTCM_OK
	} else {
		return RTCM_CRC_FAIL
	}

}
